package frogermcs.io.likeanimation.widget;

import frogermcs.io.likeanimation.ResourceTable;
import frogermcs.io.likeanimation.interpolator.AccelerateDecelerateInterpolator;
import frogermcs.io.likeanimation.interpolator.DecelerateInterpolator;
import frogermcs.io.likeanimation.interpolator.OvershootInterpolator;
import frogermcs.io.likeanimation.util.AnimatorValueUtils;
import frogermcs.io.likeanimation.util.PxUtils;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

public class LikeButtonView extends StackLayout
        implements Component.ClickedListener,
        Component.TouchEventListener {

    private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR =
            new DecelerateInterpolator();
    private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR =
            new AccelerateDecelerateInterpolator();
    private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR =
            new OvershootInterpolator(4);

    private Image ivStar;
    private DotsView vDotsView;
    private CircleView vCircle;

    private boolean isChecked;
    private AnimatorGroup animatorSet;

    public LikeButtonView(Context context) {
        this(context, null);
    }

    public LikeButtonView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public LikeButtonView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        int starSize = attrSet.getAttr("starSize").isPresent()
                ? attrSet.getAttr("starSize").get().getDimensionValue()
                : PxUtils.vp2px(getContext(), 50);
        System.out.println("==== star size : " + starSize);
        init(starSize);
    }

    private void init(int starSize) {


        LayoutScatter.getInstance(getContext())
                .parse(ResourceTable.Layout_view_like_button, this, true);
        StackLayout starLayout = (StackLayout) findComponentById(ResourceTable.Id_star_layout);
        starLayout.setWidth(starSize);
        starLayout.setHeight(starSize);
        ivStar = (Image) findComponentById(ResourceTable.Id_ivstar);

        final int size = starSize / 10 * 4;

        ivStar.setWidth(size);
        ivStar.setHeight(size);
        vDotsView = (DotsView) findComponentById(ResourceTable.Id_vDotsView);
        vDotsView.setMaxDotSize(starSize / 30);
        vCircle = (CircleView) findComponentById(ResourceTable.Id_vCircle);
        vCircle.setWidth(size);
        vCircle.setHeight(size);
        setClickedListener(this);
        setTouchEventListener(this);
    }

    @Override
    public void onClick(Component component) {

        isChecked = !isChecked;
        ivStar.setPixelMap(isChecked ? ResourceTable.Media_ic_star_rate_on :
                ResourceTable.Media_ic_star_rate_off);

        if (animatorSet != null) {
            animatorSet.cancel();
        }

        if (onStarCheckedListener != null) {
            onStarCheckedListener.onChecked(isChecked);
        }

        if (isChecked) {
            ivStar.createAnimatorProperty().cancel();
            ivStar.setScaleX(0);
            ivStar.setScaleY(0);
            vCircle.setInnerCircleRadiusProgress(0);
            vCircle.setOuterCircleRadiusProgress(0);
            vDotsView.setCurrentProgress(0);

            animatorSet = new AnimatorGroup();

            AnimatorValue outerCircleAnimator = new AnimatorValue();
            outerCircleAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float v) {
                    float animatedValue = AnimatorValueUtils.getAnimatedValue(v, 0.1f, 1f);
                    vCircle.setOuterCircleRadiusProgress(animatedValue);
                }
            });
            outerCircleAnimator.setDuration(250);
            outerCircleAnimator.setCurve(DECCELERATE_INTERPOLATOR);

            AnimatorValue innerCircleAnimator = new AnimatorValue();
            innerCircleAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float v) {
                    float animatedValue = AnimatorValueUtils.getAnimatedValue(v, 0.1f, 1f);
                    vCircle.setInnerCircleRadiusProgress(animatedValue);
                }
            });
            innerCircleAnimator.setDuration(200);
            innerCircleAnimator.setDelay(200);
            innerCircleAnimator.setCurve(DECCELERATE_INTERPOLATOR);

            AnimatorValue starScaleAnimator = new AnimatorValue();
            starScaleAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float v) {
//                    float animatedValue = AnimatorValueUtils.getAnimatedValue(v, 0.2f, 1f);
                    float animatedValue = v;
                    ivStar.setScale(animatedValue, animatedValue);
                }
            });
            starScaleAnimator.setDuration(350);
            starScaleAnimator.setDelay(250);
            starScaleAnimator.setCurve(OVERSHOOT_INTERPOLATOR);

            AnimatorValue dotsAnimator = new AnimatorValue();
            dotsAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float v) {
//                    float animatedValue = AnimatorValueUtils.getAnimatedValue(v, 0.1f, 1f);
                    vDotsView.setCurrentProgress(v);
                }
            });
            dotsAnimator.setDuration(900);
            dotsAnimator.setDelay(50);
            dotsAnimator.setCurve(ACCELERATE_DECELERATE_INTERPOLATOR);

            animatorSet.runParallel(
                    outerCircleAnimator,
                    innerCircleAnimator,
                    starScaleAnimator,
                    dotsAnimator
            );

            animatorSet.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {

                }

                @Override
                public void onStop(Animator animator) {

                }

                @Override
                public void onCancel(Animator animator) {
                    vCircle.setInnerCircleRadiusProgress(0);
                    vCircle.setOuterCircleRadiusProgress(0);
                    vDotsView.setCurrentProgress(0);
                    ivStar.setScaleX(1);
                    ivStar.setScaleY(1);
                }

                @Override
                public void onEnd(Animator animator) {
                }

                @Override
                public void onPause(Animator animator) {

                }

                @Override
                public void onResume(Animator animator) {

                }
            });

            animatorSet.start();
        }
    }

    public boolean isChecked() {
        return isChecked;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                AnimatorValue downAnimator = new AnimatorValue();
                downAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        float value = AnimatorValueUtils.getAnimatedValue(v, 1f, 0.7f);
                        ivStar.setScaleX(value);
                        ivStar.setScaleY(value);
                    }
                });
                downAnimator.setDuration(150);
                downAnimator.setCurve(DECCELERATE_INTERPOLATOR);
                downAnimator.start();
                setPressState(true);
                break;
            case TouchEvent.POINT_MOVE:
                float x = event.getPointerPosition(0).getX();
                float y = event.getPointerPosition(0).getY();
                boolean isInside = (x > 0 && x < getWidth() && y > 0 && y < getHeight());
                if (isPressed() != isInside) {
                    setPressState(isInside);
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:

                AnimatorValue upAnimatorValue = new AnimatorValue();
                final float upStart = ivStar.getScaleX();
                upAnimatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        float value = AnimatorValueUtils.getAnimatedValue(v, upStart, 1f);
                        ivStar.setScaleX(value);
                        ivStar.setScaleY(value);
                    }
                });
                upAnimatorValue.setCurve(DECCELERATE_INTERPOLATOR);
                upAnimatorValue.start();
                if (isPressed()) {
                    setPressState(false);
                }
                break;
            case TouchEvent.CANCEL:
                AnimatorValue cancelAnimatorValue = new AnimatorValue();
                final float cancelStart = ivStar.getScaleX();
                cancelAnimatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        float value = AnimatorValueUtils.getAnimatedValue(v, cancelStart, 1f);
                        ivStar.setScaleX(value);
                        ivStar.setScaleY(value);
                    }
                });
                cancelAnimatorValue.setCurve(DECCELERATE_INTERPOLATOR);
                cancelAnimatorValue.start();
                setPressState(false);
                break;
            default:
                break;
        }
        return true;
    }

    private OnStarCheckedListener onStarCheckedListener;

    public interface OnStarCheckedListener {
        public void onChecked(boolean isChecked);
    }

    public void setOnStarCheckedListener(OnStarCheckedListener onStarCheckedListener) {
        this.onStarCheckedListener = onStarCheckedListener;
    }
}
